/*
 * This file is part of the SDWebImage package.
 * (c) Olivier Poitrey <rs@dailymotion.com>
 * (c) Fabrice Aneche
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#import "NSData+GGContentType.h"
#import <MobileCoreServices/MobileCoreServices.h>

// AVFileTypeHEIC/AVFileTypeHEIF is defined in AVFoundation via iOS 11, we use this without import AVFoundation
#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic")
#define kSDUTTypeHEIF ((__bridge CFStringRef)@"public.heif")
// HEIC Sequence (Animated Image)
#define kSDUTTypeHEICS ((__bridge CFStringRef)@"public.heics")
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
#define kSVGTagEnd @"</svg>"

@implementation NSData (GGContentType)

+ (DGGImageFormat)dgg_imageFormatForImageData:(nullable NSData *)data {
    if (!data) {
        return DGGImageFormatUndefined;
    }
    
    // File signatures table: http://www.garykessler.net/library/file_sigs.html
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return DGGImageFormatJPEG;
        case 0x89:
            return DGGImageFormatPNG;
        case 0x47:
            return DGGImageFormatGIF;
        case 0x49:
        case 0x4D:
            return DGGImageFormatTIFF;
        case 0x52: {
            if (data.length >= 12) {
                //RIFF....WEBP
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
                if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                    return DGGImageFormatWebP;
                }
            }
            break;
        }
        case 0x00: {
            if (data.length >= 12) {
                //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
                if ([testString isEqualToString:@"ftypheic"]
                    || [testString isEqualToString:@"ftypheix"]
                    || [testString isEqualToString:@"ftyphevc"]
                    || [testString isEqualToString:@"ftyphevx"]) {
                    return DGGImageFormatHEIC;
                }
                //....ftypmif1 ....ftypmsf1
                if ([testString isEqualToString:@"ftypmif1"] || [testString isEqualToString:@"ftypmsf1"]) {
                    return DGGImageFormatHEIF;
                }
            }
            break;
        }
        case 0x25: {
            if (data.length >= 4) {
                //%PDF
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(1, 3)] encoding:NSASCIIStringEncoding];
                if ([testString isEqualToString:@"PDF"]) {
                    return DGGImageFormatPDF;
                }
            }
        }
        case 0x3C: {
            if (data.length > 100) {
                // Check end with SVG tag
                NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 100, 100)] encoding:NSASCIIStringEncoding];
                if ([testString containsString:kSVGTagEnd]) {
                    return DGGImageFormatSVG;
                }
            }
        }
    }
    return DGGImageFormatUndefined;
}

+ (nonnull CFStringRef)dgg_UTTypeFromImageFormat:(DGGImageFormat)format {
    CFStringRef UTType;
    switch (format) {
        case DGGImageFormatJPEG:
            UTType = kUTTypeJPEG;
            break;
        case DGGImageFormatPNG:
            UTType = kUTTypePNG;
            break;
        case DGGImageFormatGIF:
            UTType = kUTTypeGIF;
            break;
        case DGGImageFormatTIFF:
            UTType = kUTTypeTIFF;
            break;
        case DGGImageFormatWebP:
            UTType = kSDUTTypeWebP;
            break;
        case DGGImageFormatHEIC:
            UTType = kSDUTTypeHEIC;
            break;
        case DGGImageFormatHEIF:
            UTType = kSDUTTypeHEIF;
            break;
        case DGGImageFormatPDF:
            UTType = kUTTypePDF;
            break;
        case DGGImageFormatSVG:
            UTType = kUTTypeScalableVectorGraphics;
            break;
        default:
            // default is kUTTypeImage abstract type
            UTType = kUTTypeImage;
            break;
    }
    return UTType;
}

+ (NSString *)dgg_imageFormatStringForImageData:(nullable NSData *)data{
    DGGImageFormat format = [self.class dgg_imageFormatForImageData:data];
    CFStringRef typeStr = [self.class dgg_UTTypeFromImageFormat:format];
    if(typeStr){
        return (__bridge NSString *)(typeStr);
    }
    return @"";
}

+ (DGGImageFormat)dgg_imageFormatFromUTType:(CFStringRef)uttype {
    if (!uttype) {
        return DGGImageFormatUndefined;
    }
    DGGImageFormat imageFormat;
    if (CFStringCompare(uttype, kUTTypeJPEG, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatJPEG;
    } else if (CFStringCompare(uttype, kUTTypePNG, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatPNG;
    } else if (CFStringCompare(uttype, kUTTypeGIF, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatGIF;
    } else if (CFStringCompare(uttype, kUTTypeTIFF, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatTIFF;
    } else if (CFStringCompare(uttype, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatWebP;
    } else if (CFStringCompare(uttype, kSDUTTypeHEIC, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatHEIC;
    } else if (CFStringCompare(uttype, kSDUTTypeHEIF, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatHEIF;
    } else if (CFStringCompare(uttype, kUTTypePDF, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatPDF;
    } else if (CFStringCompare(uttype, kUTTypeScalableVectorGraphics, 0) == kCFCompareEqualTo) {
        imageFormat = DGGImageFormatSVG;
    } else {
        imageFormat = DGGImageFormatUndefined;
    }
    return imageFormat;
}

@end
